﻿using Anderson.NetLobby.MessageContent;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;

namespace Anderson.NetLobby.Common
{
    public class NetLobbySession
    {
        public Socket playerSocket;
        private INetLobbyLog logger;

        public long playerId;
        public bool playerIdConfirmed;
        public string playerCode;
        public long playerHeadImageId;
        public DateTime playerLoginTime;
        public bool playerInRoom;
        public long roomId;

        public const int BufferSize = 1024;
        public byte[] buffer = new byte[BufferSize];
        public List<byte> package = new List<byte>();

        private static long nextPlayerId = 0;
        public static long GetNextPlayerId()
        {
            return Interlocked.Increment(ref nextPlayerId);
        }

        public NetLobbySession()
        {
            playerIdConfirmed = false;
            playerInRoom = false;

            playerId = GetNextPlayerId();
            playerCode = "";
            playerHeadImageId = 0L;
            package.Clear();

            playerLoginTime = DateTime.Now;
        }

        public NetLobbySession(Socket socket, string userCode, long imageId, DateTime loginTime, INetLobbyLog logger) : this()
        {
            playerSocket = socket;
            this.logger = logger;

            playerCode = userCode;
            playerHeadImageId = imageId;

            playerLoginTime = loginTime;
        }

        public void ServerSideClose(SemaphoreSlim semaphore)
        {
            try
            {
                if (null != playerSocket && playerSocket.Connected)
                {
                    playerSocket.Shutdown(SocketShutdown.Both);
                    playerSocket.Close();

                    playerSocket = null;
                }

                semaphore.Release();
            }
            catch (Exception e)
            {
                logger.LogError(e.Message);
            }
        }

        public void ClientSideClose()
        {
            try
            {
                if (null != playerSocket && playerSocket.Connected)
                {
                    playerSocket.Shutdown(SocketShutdown.Both);
                    playerSocket.Close();

                    playerSocket = null;
                }
            }
            catch (Exception e)
            {
                logger.LogError(e.Message);
            }
        }

        public byte[] ReceiveMessage(byte[] readBytes)
        {
            package.AddRange(readBytes);

            int countOfPackage = package.Count;
            if (countOfPackage < 4)
            {
                //消息未接收全
                return null;
            }

            byte[] result = null;
            byte[] temp = null;

            byte[] bytesOfPackage = package.ToArray();
            ByteStream byteStream = new ByteStream(bytesOfPackage);
            uint length = byteStream.ReadUInt32();

            int fullMessageSize = sizeof(uint) + (int)length;
            if (countOfPackage >= fullMessageSize)
            {
                package.Clear();

                //设置返回值
                result = new byte[fullMessageSize];
                Buffer.BlockCopy(bytesOfPackage, 0, result, 0, fullMessageSize);

                //多余的字节放回package
                if (countOfPackage > fullMessageSize)
                {
                    temp = new byte[countOfPackage - fullMessageSize];
                    Buffer.BlockCopy(bytesOfPackage, fullMessageSize, temp, 0, countOfPackage - fullMessageSize);

                    package.AddRange(temp);
                }
            }//if

            return result;
        }//ReceiveMessage


        #region SendPlayerId        
        internal void SendPlayerId()
        {
            logger.Log("Command to client to Confirm id.");

            MC_PlayerId setPlayerId = new MC_PlayerId();
            setPlayerId.idFromServer = playerId;

            NetMessage<MC_PlayerId> netMessage = new NetMessage<MC_PlayerId>(
                0L,//RoomId，但该信息发送时用户还没有加入任何房间，所以不需要房间编号
                MessageLevelDefinition.SERVER_L1_SYSTEM,
                MessageLevelDefinition.SERVER_L2_SYSTEM_PLAYERID,
                MessageLevelDefinition.SERVER_L3_SYSTEM_PLAYERID_CMD,
                setPlayerId);

            byte[] bytes = MessageSerialize.Serialize(netMessage);

            playerSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(SendPlayerIdCallback), playerSocket);
        }

        internal void SendPlayerIdCallback(IAsyncResult ar)
        {
            logger.Log("Command to client to Confirm id end.");

            try
            {
                Socket handler = (Socket)ar.AsyncState;

                handler.EndSend(ar);
            }
            catch (Exception e)
            {
            }
        }

        internal void ExitRoom()
        {
            playerInRoom = false;
            roomId = 0;
        }
        #endregion
    }//class
}//namespace
